/**
 * Huize Service Inc
 * All Rights Reserved @2018
 */

package com.huize.zhike.framework.common.util;

import com.huize.ladon.apm.common.constant.CommonConstants;
import com.huize.ladon.apm.common.util.MixAllUtils;
import com.huize.zhike.framework.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 常规工具类
 *
 * @author tianyuliang
 * @version $Id: BaseUtils.java, v0.1 2020/3/19 19:57 tianyuliang Exp $$
 */
@SuppressWarnings("unchecked")
@Slf4j
public class BaseUtils extends MixAllUtils {

    /**
     * 计算耗时操作，单位ms
     */
    public static long computeTime(final long t0) {
        return (System.currentTimeMillis() - t0);
    }

    /**
     * 计算集合size大小
     *
     * @param values
     * @return
     */
    public static int size(Collection<?> values) {
        return isNotEmpty(values) ? values.size() : 0;
    }

    /**
     * 转为Integer类型
     *
     * @param value
     * @param defaultValue
     * @return
     */
    public static Double parseDouble(Object value, Double defaultValue) {
        try {
            return Double.parseDouble(BaseUtils.toDefaultString(value));
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 获取UUID字符串(去掉-短横线)
     *
     * @return
     */
    public static String buildSimpleUuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 获取UUID字符串(保留原始字符串长度)
     *
     * @return
     */
    public static String buildSpecialUuid() {
        return UUID.randomUUID().toString();
    }

    /**
     * 产生在[Min, Max)范围内的随机数
     *
     * @param min
     * @param max
     * @return
     */
    public static int buildRandom(int min, int max) {
        int value = RandomUtils.nextInt(min, max);
        return value;
    }

    /**
     * 产生在[1, 150)范围内的随机数
     *
     * @return
     */
    public static int buildUseTimeRandom() {
        return buildRandom(1, 150);
    }


    /**
     * 构建任意字符串
     *
     * @param object
     * @return
     */
    public static String toDefaultString(Object object) {
        return object == null ? StringUtils.EMPTY : object.toString();
    }

    /**
     * 聚合某个特殊列表
     *
     * @param values
     * @return
     */
    public static String reduceKey(List<String> values) {
        String reduce = BaseUtils.defaultList(values).stream().map(v -> StringUtils.trimToEmpty(v)).collect(Collectors.joining(CommonConstants.SPECIAL_HOLDER));
        return reduce;
    }

    /**
     * 校验文件路径是否存在,不存在则创建
     *
     * @param distPath
     */
    public static void checkDirIfNotCreate(String distPath) {
        File distFile = new File(distPath);
        if (distFile.isFile() || distFile.exists()) {
            return;
        }
        if (!distFile.exists()) {
            try {
                distFile.mkdir();
            } catch (Exception e) {
                String msg = "create dir error. distPath=" + distPath;
                throw new BizException(msg, e);
            }
        }
    }

    /**
     * 是否为windows操作系统
     *
     * @return
     */
    public static boolean isWindowsSystem() {
        String osName = System.getProperty("os.name");
        return StringUtils.containsIgnoreCase(osName, "Windows");
    }

    /**
     * 是否为linux操作系统
     *
     * @return
     */
    public static boolean isLinuxSystem() {
        String osName = System.getProperty("os.name");
        return StringUtils.containsIgnoreCase(osName, "linux");
    }

    /**
     * 获取本机IP地址
     */
    public static String getLocalIp() {
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip = null;
            while (interfaces.hasMoreElements()) {
                NetworkInterface netInterface = interfaces.nextElement();
                if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
                    continue;
                }
                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    ip = addresses.nextElement();
                    if (ip != null && ip instanceof Inet4Address) {
                        String strIp = ip.getHostAddress();
                        return strIp;
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取本机IP地址异常. {}", e.getMessage(), e);
        }
        return "";
    }

    /**
     * Linux系统 构用户目录
     *
     * @return
     */
    public static String buildUserDir() {
        String dir = System.getProperty("user.dir") + File.separator;
        return dir;
    }


    /**
     * 默认非空LinkedHashMap
     *
     * @param source
     * @return
     */
    public static LinkedHashMap<String, Object> defaultLinkHashMap(LinkedHashMap<String, Object> source) {
        return source != null ? source : new LinkedHashMap<>();
    }

    /**
     * 修正windows系统文件名称
     *
     * @param fileLocalName
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String fixWindowsFileName(String fileLocalName) throws UnsupportedEncodingException {
        if (BaseUtils.isWindowsSystem() && isNotEmpty(fileLocalName)) {
            String values[] = fileLocalName.replace("\\", "/").split("/");
            String oldValue = values[values.length - 1];
            String fileName = oldValue.replaceFirst(oldValue, URLEncoder.encode(oldValue, CommonConstants.UTF8));
            values[values.length - 1] = fileName;
            String result = Stream.of(values).collect(Collectors.joining(File.separator + File.separator));
            return result;
        }
        return trimToEmpty(fileLocalName);
    }

    /**
     * 集合第一项是有效的
     */
    public static boolean existFirstElement(List source) {
        Object first = firstElement(source);
        return first != null;
    }

    /**
     * 获取文件路径，该文件要求与clazz处于同一级目录
     */
    public static String buildTestFileLocalPath(Class<?> clazz, String fileName) {
        return MixAllUtils.buildFileLocalPath(clazz, CommonConstants.TEST_CASE_CHILDREN_DIR, fileName);
    }

    /**
     * 获取文件路径，该文件要求与clazz处于同一级目录
     */
    public static String buildSourceFileLocalPath(Class<?> clazz, String fileName) {
        return MixAllUtils.buildFileLocalPath(clazz, CommonConstants.MAIN_CASE_CHILDREN_DIR, fileName);
    }


    /**
     * 校验能否转为Double类型
     *
     * @param value
     * @return
     */
    public static Boolean canParseDouble(Object value) {
        try {
            Double.valueOf(value.toString());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 校验能否转为Double类型
     *
     * @param value
     * @return
     */
    public static Double parseDouble(Object value) {
        return parseDouble(value, 0D);
    }


    /**
     * URL解码
     */
    public static String urlDecoder(String value) {
        try {
            return StringUtils.isNotBlank(value) ? URLDecoder.decode(StringUtils.trimToEmpty(value), CommonConstants.UTF8) : "";
        } catch (UnsupportedEncodingException e) {
            return "";
        } catch (Exception e) {
            return StringUtils.trimToEmpty(value);
        }
    }

    /**
     * 解码字节码
     *
     * @param data    字符串
     * @param charset 字符集，如果此字段为空，则解码的结果取决于平台
     * @return 解码后的字符串
     */
    public static String buildString(byte[] data, Charset charset) {
        if (data == null) {
            return null;
        }

        if (null == charset) {
            return new String(data);
        }
        return new String(data, charset);
    }

    /**
     * 编码字符串
     *
     * @param str     字符串
     * @param charset 字符集，如果此字段为空，则解码的结果取决于平台
     * @return 编码后的字节码
     */
    public static byte[] buildBytes(CharSequence str, Charset charset) {
        if (str == null) {
            return null;
        }

        if (null == charset) {
            return str.toString().getBytes();
        }
        return str.toString().getBytes(charset);
    }

    /**
     * 包装 {@link System#arraycopy(Object, int, Object, int, int)}<br>
     * 数组复制，缘数组和目标数组都是从位置0开始复制
     *
     * @param src    源数组
     * @param dest   目标数组
     * @param length 拷贝数组长度
     * @return 目标数组
     * @since 3.0.6
     */
    public static Object copy(Object src, Object dest, int length) {
        //noinspection SuspiciousSystemArraycopy
        System.arraycopy(src, 0, dest, 0, length);
        return dest;
    }

    /**
     * foreach遍历增加索引
     *
     * @param startIndex 启始索引
     * @param elements   集合对象
     * @param action
     * @param <T>
     */
    public static <T> void forEach(Integer startIndex, Iterable<? extends T> elements, BiConsumer<Integer, ? super T> action) {
        Objects.requireNonNull(elements);
        Objects.requireNonNull(action);
        for (T element : elements) {
            action.accept(startIndex++, element);
        }
    }

    /**
     * 匹配在index索引范围内的所有事件（不包括自己）
     */
    public static <T> List<T> matchPrevious(List<T> values, Integer index) {
        if (BaseUtils.isEmpty(values)) {
            return new ArrayList<>();
        }
        if (BaseUtils.parseInteger(index) < 0 || index >= values.size() || index < 0) {
            throw new BizException("参数索引无效!");
        }

        long maxSize = index;
        List<T> dtos = values.stream().limit(maxSize).collect(Collectors.toList());
        return dtos;
    }

    /**
     * 给源字符串开始、结尾都包裹 通配符,例如 product --> 'product' 构建mysql模糊匹配参数
     *
     * @param keyword
     * @return
     */
    public static String fieldSingleWrapper(String keyword) {
        return "'" + trimToEmpty(keyword).replace("'", "\\'") + "'";
    }

    /**
     * SQL字符串转义
     */
    public static String escapePropertyValue(String propertyValue) {
        String value = StringUtils.trimToEmpty(propertyValue)
                .replace("$", "\\$")
                .replace("^", "\\^")
                .replace("'", "\\'")
                .replace("%", "\\%")
                .replace("[", "\\[")
                .replace("]", "\\]");
        return value;
    }

    /**
     * SQL字符串转义-特殊处理
     */
    public static String escapeSpecialPropertyValue(String propertyValue) {
        String value = StringUtils.trimToEmpty(propertyValue)
                .replace("$", "\\$")
                .replace("^", "\\^")
                .replace("%", "\\%")
                .replace("[", "\\[")
                .replace("]", "\\]");
        return value;
    }

    public static void main(String[] args) {


    }

}
